Skip to content

Install ovphysx wheel by default in --install#5780

Merged
AntoineRichard merged 18 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/ovphysx-default-install
Jun 9, 2026
Merged

Install ovphysx wheel by default in --install#5780
AntoineRichard merged 18 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/ovphysx-default-install

Conversation

@AntoineRichard

@AntoineRichard AntoineRichard commented May 26, 2026

Copy link
Copy Markdown
Collaborator

Description

Promote the publicly available ovphysx PyPI wheel out of the manual ov[ovphysx] extra and into the default ./isaaclab.sh --install flow, mirroring how the newton wheel is treated. The OVRTX renderer wheel stays opt-in via --install 'ov[ovrtx]' or --install 'ov[all]'.

Concretely:

  • MANUAL_EXTRA_FEATURES drops "ov" (it now only contains "contrib"), so the ov feature is part of the automatic -i / -i all set alongside newton, rl, and visualizer.
  • _install_ov_extra_dependencies("") no longer prints a help message and returns; it now installs isaaclab_ovphysx[ovphysx]. Explicit ov[ovrtx], ov[ovphysx], and ov[all] behavior is unchanged.
  • CLI --install help text and the command_install docstring are updated to reflect the new default.
  • With the wheel guaranteed in every standard install, the pytest.importorskip("ovphysx.types", reason="ovphysx wheel not installed") guards (9 sites) and one inner importorskip("isaaclab_ovphysx.tensor_types") call are removed from the isaaclab_ovphysx test suite. The isaaclab_ov CI job (whose filter-pattern: "isaaclab_ov" already collects these tests) now exercises them for real instead of silently skipping.

No new required dependency is added; source/isaaclab_ovphysx/setup.py already declared EXTRAS_REQUIRE = {"ovphysx": ["ovphysx"]}. The extra remains unpinned for now — pinning a minimum version is a sensible follow-up once we lock in a release.

Fixes # (n/a)

Type of change

  • New feature (non-breaking change which adds functionality)

Strictly, the default install footprint grows by one PyPI wheel and previously-skipped tests now run, so downstream consumers of --install see new behavior — but no public API is removed or renamed and all existing ov[...] selectors continue to work as before.

Screenshots

N/A — install-CLI and test-gating change.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation (CLI --help text and command_install docstring updated)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works (new test_all_installs_ov_with_default_ovphysx_selector plus updates to test_manual_extra_features and test_all_does_not_install_manual_extra_dependencies; 51/51 pass in test_install_command_parsing.py)
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package — source/isaaclab/changelog.d/antoiner-ovphysx-default-install.rst and source/isaaclab_ovphysx/changelog.d/antoiner-ovphysx-default-install.rst
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

This is a well-structured PR that promotes the ovphysx wheel from opt-in to default installation, aligning with how the Newton wheel is already treated. The implementation is clean and the test updates are thorough.

✅ Strengths

  1. Consistent design pattern: Following the existing Newton wheel approach makes the codebase more predictable and the install experience more uniform.

  2. Improved test reliability: Removing the importorskip guards means missing the ovphysx wheel in CI will now fail loudly rather than silently skipping tests — this catches real regressions rather than masking them.

  3. Good documentation: Both changelog fragments clearly explain the change, and the help text in __init__.py is updated to reflect the new behavior.

  4. Comprehensive test updates: All 8 test files were updated to remove the skip guards, and test_install_command_parsing.py includes a new test (test_all_installs_ov_with_default_ovphysx_selector) to verify the auto-install path.

💭 Minor Observations

  1. No version pin on ovphysx (noted by author): The PR description mentions setup.py has "ovphysx": ["ovphysx"] with no version constraint. This is fine for now, but consider adding a minimum version pin once a stable release is identified to prevent potential compatibility issues.

  2. CI job monitoring (noted by author): Since isaaclab_ov will now actually exercise the ovphysx tests, worth watching the first few CI runs to catch any previously-hidden issues. This is already acknowledged in the test plan.

🔍 Implementation Notes

The logic change in _install_ov_extra_dependencies() is clean:

  • Empty selector → defaults to {"ovphysx"}
  • Non-empty selector → validates and processes as before
  • OVRTX remains opt-in via explicit ov[ovrtx] or ov[all]

The behavior for explicit selectors (ov[ovrtx], ov[all], ov[ovphysx]) is unchanged, which minimizes risk for users who already use those.


Overall this is a straightforward, well-tested change that improves the default user experience while maintaining backward compatibility for explicit install commands.


Update (commit c37a233): The PR direction has substantially changed — ovphysx is no longer auto-installed by --install all. Instead, ov is now in MANUAL_EXTRA_FEATURES and CI jobs explicitly install the wheel via extra-pip-packages. The importorskip guards have been re-added to all test files (graceful skip when wheel is absent).

Key changes in this iteration:

  1. Reversed default-install approachov moved to manual extras; _install_ov_extra_dependencies() now prints a help message and returns early when called without a selector. This is a more conservative approach that avoids forcing the wheel on all users.

  2. New device_split pytest marker + CI infratools/_device_split.py and a significant refactor of tools/conftest.py to run marked test files once per device (CPU/GPU) in separate subprocesses, working around the ovphysx ≤0.3.7 process-global device lock.

  3. conftest.py refactor — The monolithic run_individual_tests loop was cleanly decomposed into _run_one_pass() + _merge_pass_status() + _PassContext dataclass. Good separation of concerns.

  4. Test infrastructuretools/test_device_split.py provides solid unit test coverage for the new marker detection logic.

Assessment: The new direction is well-reasoned — keeping the wheel opt-in avoids download/install overhead for users who don't need it, while CI explicitly installs it for coverage. The device_split mechanism is a practical workaround for the ovphysx device-lock limitation and the refactoring of conftest.py improves maintainability. No new issues identified.---

Update (commit a47511b): Significant scope expansion. The PR now bundles multiple Newton, isaaclab_ov, and isaaclab_ovphysx improvements beyond the original ovphysx install change:

New changes reviewed:

  1. Newton projected_gravity_b kernels — Dedicated 1D/2D kernels that normalize per-env gravity on read, enabling per-env gravity randomization to propagate correctly. GRAVITY_VEC_W now binds directly to model.gravity instead of copying env 0's value. Clean design.

  2. Timestamp guard for stale sensor data (#4970) — Contact sensor, IMU, PVA, and joint-wrench kernels now skip envs with timestamp == 0.0 (not stepped since reset). Prevents stale pre-reset data from leaking through. Each sensor has a corresponding regression test.

  3. collision_decimation config — Mid-tick re-collision support with proper gating (0 = disabled, must be < num_substeps). Warning logged when misconfigured. Well-tested with counting mock.

  4. Per-world sites (per_world=True) — Extends cl_register_site for bodyless sites per cloned world frame. Clean integration into _cl_inject_sites / _cl_inject_sites_fallback / newton_replicate.

  5. NewtonSiteFrameView refactor — Major simplification: removed duplicate non-indexed kernels, removed parent-relative local-pose machinery, added ClonePlan-aware site resolution. ~800 lines removed, cleaner architecture.

  6. Asset initialization cleanup — All three backends (Newton, OvPhysX, OvRTX) now use shared resolve_matching_prims_from_source() + get_all_matching_child_prims() with expected_num_matches=1 instead of duplicated boilerplate.

  7. Legacy OVRTX 0.2.x removal — Removed _IS_OVRTX_0_3_0_OR_NEWER gates, legacy kernels, temp-file fallback. Minimum is now 0.3.0.

  8. pyproject.toml modernizationisaaclab_newton, isaaclab_ov, isaaclab_ovphysx all migrated from setup.py + extension.toml to declarative pyproject.toml. Clean.

Previous review concerns: Still addressed (no regressions from the c37a233 changes).

Assessment: No new issues found. The code is well-structured, properly tested (new regression tests for each behavioral change), and follows consistent patterns across the three packages.


Update (1fce150): The device_split pytest marker and its entire infrastructure (tools/_device_split.py, tools/test_device_split.py, the _PassContext/_run_one_pass/_merge_pass_status refactor in conftest.py) have been removed. The conftest.py is reverted to the simpler flat loop structure. The pytestmark = pytest.mark.device_split lines are removed from the two ovphysx test files, and the marker definition is dropped from pyproject.toml. The device-split changelog fragment is replaced with a .skip file.

This simplification suggests the ovphysx device-lock workaround is no longer needed (perhaps resolved upstream or the tests now handle device parametrization without separate-process isolation). The resulting conftest.py is cleaner and easier to maintain. No new issues introduced.


Update (2dba76d): Three new commits pushed (revert + changelog skip + restore). Net diff from previously reviewed SHA (a47511b4) is zero — the tree is identical. The device_split infrastructure, conftest refactor, and all test markers are back in place as previously reviewed. No new issues.


Update (6653d32): New commit adds Kit/runtime version logging to AppLauncher startup — a _log_kit_version_info() method prints Kit version, kernel version, and git hash to stderr for diagnostics. Accompanying changelog fragment added. Clean, no issues.


Update (5f232fb): Three additional test files now have the pytestmark = pytest.mark.device_split marker added:

  • isaaclab_ovphysx/test/assets/test_articulation.py
  • isaaclab_ovphysx/test/assets/test_rigid_object.py
  • isaaclab_ovphysx/test/assets/test_rigid_object_collection.py

This extends the device-split infrastructure to cover the ovphysx asset tests that were previously missing the marker. Consistent with the earlier device_split pattern — these files likely need separate CPU/GPU subprocess isolation due to the ovphysx process-global device lock. No issues.


Update (c746eaa): Minor improvements to the device_split infrastructure:

  1. is_device_split_file() now accepts an optional source parameter to avoid redundant file I/O when the test content is already loaded in conftest.py.
  2. conftest.py passes the preloaded test_content to the function — eliminates a double-read.
  3. ✅ New unit test test_preloaded_source covers the new parameter path.
  4. ✅ Changelog fragment updated to list all 5 device-split test files (was previously 2).

Clean, no issues. Good housekeeping commit.

@greptile-apps

greptile-apps Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR promotes the ovphysx wheel from an opt-in extra (ov[ovphysx]) into the default ./isaaclab.sh --install flow, matching Newton's treatment, while keeping the OVRTX renderer wheel explicitly opt-in. The companion change removes the pytest.importorskip("ovphysx.types") skip-guards across the isaaclab_ovphysx test suite so tests now fail loudly if the wheel is missing.

  • install.py / __init__.py: ov removed from MANUAL_EXTRA_FEATURES; _install_ov_extra_dependencies now defaults an empty selector to {\"ovphysx\"} instead of printing an info message and returning early. All four selector paths (\"\", ovphysx, ovrtx, all) behave correctly.
  • Test suite guard removal: pytest.importorskip(\"ovphysx.types\") and the per-test importorskip(\"isaaclab_ovphysx.tensor_types\") guards are deleted from 7 test files; import pytest is dropped from files where it was only used for those guards; # noqa: E402 annotations on now-correctly-ordered top-level imports are cleaned up.
  • Install CI tests: test_manual_extra_features updated, new test_all_installs_ov_with_default_ovphysx_selector added, two test methods renamed to drop the manual_ prefix from their names.

Confidence Score: 4/5

Safe to merge; install logic, dispatch tests, and guard removal are all internally consistent. The only thing worth a follow-up is a redundant module-level import left in one helper test file.

The install-CLI changes are correct and well-covered by the updated test suite. The guard-removal sweep across the seven test files is clean — import pytest is dropped only in files that had no remaining pytest.* API calls, and pytest fixtures like monkeypatch/caplog are injected by the framework without a direct import. The one minor leftover is a duplicated MockOvPhysxBindingSet import inside test_mock_binding_set_rigid_object_shapes in test_articulation_helpers.py, which was pre-existing but is more visible now that the module-level import sits right above it. No functional defects found.

source/isaaclab_ovphysx/test/assets/test_articulation_helpers.py — has a redundant inner import of MockOvPhysxBindingSet that mirrors the module-level import added by this PR.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/cli/commands/install.py Removes ov from MANUAL_EXTRA_FEATURES and rewires _install_ov_extra_dependencies so an empty selector defaults to ovphysx; logic is correct and all four selector paths behave as intended.
source/isaaclab/test/install_ci/test_install_command_parsing.py Tests correctly updated: MANUAL_EXTRA_FEATURES assertion tightened to just contrib, new test verifies ov is auto-installed with empty selector for -i all, two test renames clarified.
source/isaaclab_ovphysx/test/physics/test_ovphysx_scene_data_backend.py Removed importorskip guard and import pytest; file never calls pytest.xxx directly (uses monkeypatch/caplog as injected fixtures only), so removal is correct.
source/isaaclab_ovphysx/test/assets/test_articulation_helpers.py importorskip guard removed, import pytest dropped, but MockOvPhysxBindingSet is now imported redundantly at module level and again inside test_mock_binding_set_rigid_object_shapes.
source/isaaclab_ovphysx/test/assets/test_articulation.py importorskip guard and trailing noqa comments removed cleanly; imports now appear at the top in natural order.
source/isaaclab_ovphysx/test/sensors/test_contact_sensor.py importorskip guard and noqa annotations removed cleanly; pytest import retained as it is still used for test decorators.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["./isaaclab.sh --install [token]"] --> B{token?}
    B -- "all / empty" --> C[Auto-install VALID_EXTRA_FEATURES minus MANUAL_EXTRA_FEATURES]
    C --> D["newton, rl, visualizer, ov (empty selector)"]
    D --> E["_install_ov_extra_dependencies('')"]
    E --> F["selectors = {'ovphysx'}"]
    F --> G["pip install isaaclab_ovphysx[ovphysx]"]
    B -- "ov" --> E
    B -- "ov[ovrtx]" --> H["_install_ov_extra_dependencies('ovrtx')"]
    H --> I["selectors = {'ovrtx'}"]
    I --> J["pip install isaaclab_ov[ovrtx]"]
    B -- "ov[all]" --> K["_install_ov_extra_dependencies('all')"]
    K --> L["selectors expanded to {'ovrtx','ovphysx'}"]
    L --> G
    L --> J
    B -- "none" --> O["Core submodules only — no extras"]
    B -- "contrib" --> P["MANUAL: requires explicit flag, never auto-installed"]
Loading

Comments Outside Diff (1)

  1. source/isaaclab_ovphysx/test/assets/test_articulation_helpers.py, line 115-119 (link)

    P2 The MockOvPhysxBindingSet import inside the function body duplicates the module-level import directly above it. With the importorskip guard gone, the inner import no longer serves as a conditional guard, so it can simply be removed.

Reviews (1): Last reviewed commit: "Install ovphysx wheel by default in `--i..." | Re-trigger Greptile

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label May 26, 2026

@kellyguo11 kellyguo11 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is making ovphysx installable by default mostly for the CI tests? I feel like it could be kept as an optional dependency from user perspective, but we can force an install of it for our CI jobs?

@AntoineRichard

Copy link
Copy Markdown
Collaborator Author

is making ovphysx installable by default mostly for the CI tests? I feel like it could be kept as an optional dependency from user perspective, but we can force an install of it for our CI jobs?

Yes it's mostly for CI tests. Sure we could leave that optional and handle it similarly to OvRTX in the CI.

Pure refactor; behavior unchanged. Enables the follow-up commit to invoke
the helper twice per file for the device_split marker without duplicating
the ~200-line retry/timeout/parse pipeline.
Resolves the ovphysx<=0.3.7 gap G5 device lock for any CI test file
that opts in via 'pytestmark = pytest.mark.device_split'. Each pass
gets its own subprocess, its own JUnit XML, and the merged counts are
written under the original file key so the summary table is unchanged.
Avoids the ovphysx<=0.3.7 gap G5 device-lock failure surfaced by PR 5780
in the isaaclab_ov CI job. The conftest device_split runner splits this
file into separate CPU and GPU subprocesses.
Avoids the ovphysx<=0.3.7 gap G5 device-lock failure on the
test_no_contact_reporting case that runs after GPU-parametrized cases
in the isaaclab_ov CI job.
Two tiny cleanups on the device_split CI machinery added in this PR:

* Remove _PassContext.is_cold_cache_test — set by the caller but never
  read by _run_one_pass; the cold-cache buffer is applied to timeout
  and startup_deadline before the dataclass is built, so the field
  was purely informational.
* Add a presence check before appending to failed_tests so a
  device_split file failing on both CPU and GPU passes only appears
  once in the 'failed tests:' debug print (exit code is unaffected;
  it derives from test_status keys).
Install ovphysx explicitly in CI jobs that exercise OV coverage instead of adding it to the default user install path.

Restore optional OVPhysX test guards so local and partial installs skip when the runtime wheel is absent.
@AntoineRichard
AntoineRichard force-pushed the antoiner/ovphysx-default-install branch from c37a233 to a47511b Compare June 1, 2026 12:10
@isaaclab-review-bot

Copy link
Copy Markdown
Contributor

Review Update (commit 2dba76d): The device_split infrastructure has been restored in this latest commit ("Restore automatic ovphysx device split").

What's back:

  1. tools/_device_split.py — Module with is_device_split_file() predicate and DEVICE_SPLIT_PASSES constant ([("-cpu", "cpu or not cuda"), ("-cuda", "cuda")]).

  2. tools/conftest.py refactor_PassContext dataclass, _run_one_pass() helper, _merge_pass_status() for combining multi-pass results. The main run_individual_tests() loop now detects device_split markers and invokes files once per device.

  3. tools/test_device_split.py — Unit tests for the predicate: single-mark, list-form, no-mark, comment-only (shouldn't match), unrelated pytestmark, missing file.

  4. Test file markerstest_views_xform_prim_ovphysx.py and test_contact_sensor.py both declare pytestmark = pytest.mark.device_split.

  5. pyproject.toml — The device_split marker is registered with a descriptive docstring explaining the ovphysx ≤0.3.7 gap G5 workaround.

  6. CI workflowextra-pip-packages: "ovrtx ovphysx" added to the isaaclab_ov job in build.yaml.

  7. Changelog — New fragment antoiner-ovphysx-device-split-ci.rst explaining the fix.

Assessment: The restoration is clean and complete. The implementation is sound — detecting the marker via regex on the source file avoids import-time side effects, and the two-pass -k expressions correctly partition CPU vs GPU parametrized tests. The _merge_pass_status() logic properly combines counters and selects the most severe result. The unit tests cover the expected detection edge cases.

No new issues found. The PR is in good shape for final human review.

@isaaclab-review-bot

Copy link
Copy Markdown
Contributor

Update (dbd83a4): Latest commit improves CI summary visibility for device_split tests:

  1. Extended device_split coverage — Three additional test files now marked with pytestmark = pytest.mark.device_split:

    • test_articulation.py
    • test_rigid_object.py
    • test_rigid_object_collection.py
  2. Improved test summary output — The _merge_pass_status() function now tracks which passes ran (CPU, GPU, or single) via a passes list. The per-test summary table gains a new "Runs" column showing e.g. cpu+gpu for device-split files, making it clearer which test files ran multi-pass.

Assessment: Clean enhancement. The additional device_split markers extend the ovphysx device-lock workaround to more test files that likely have the same issue. The summary table improvement provides better observability without changing test behavior. No issues identified.

@AntoineRichard

Copy link
Copy Markdown
Collaborator Author

@myurasov-nv @hujc7 any opinions on the auto split cpu/gpu device.

@hujc7

hujc7 commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

@myurasov-nv @hujc7 any opinions on the auto split cpu/gpu device.

This is great. The only concern is that it sits more in the test logic as well as the retries, which is not always obvious at test level (I think it's mostly for the process lock issue?). I also have something in #5823 which more relies on @pytest.mark.parametrize("device", test_devices()).

Btw, I saw ovphysx has newer version. Is the process-global device lock still a problem?

@AntoineRichard

Copy link
Copy Markdown
Collaborator Author

@myurasov-nv @hujc7 any opinions on the auto split cpu/gpu device.

This is great. The only concern is that it sits more in the test logic as well as the retries, which is not always obvious at test level (I think it's mostly for the process lock issue?). I also have something in #5823 which more relies on @pytest.mark.parametrize("device", test_devices()).

Btw, I saw ovphysx has newer version. Is the process-global device lock still a problem?

Thanks for taking a look! About 5823 the difference here is the device lock, we cannot run the cpu and gpu tests in the same run, we need to launch two separate test instances to test on all the devices. This is why it sits there. It could also be hard-coded, but that sounds like a bad idea?

Yeah, the new version will still have the device lock. I don't think they are planning on removing the lock at all.


* Re-enabled both CPU and GPU coverage in CI for
:file:`test/sim/test_views_xform_prim_ovphysx.py` and
:file:`test/sensors/test_contact_sensor.py` by tagging them with the new

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: some more files were tagged with that

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in c746eaa: the changelog now lists all five OVPhysX test files tagged with device_split.

Comment thread tools/conftest.py

timeout = test_settings.PER_TEST_TIMEOUTS.get(file_name, test_settings.DEFAULT_TIMEOUT)

# Read the test file once for cold-cache and device-split detection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think test_content is read below and also in is_device_split_file, could be worth passing the contents to save one read

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c746eaa: is_device_split_file now accepts preloaded source text, and tools/conftest.py passes the test_content it already read. Added a unit test for that path.

isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_ov"
extra-pip-packages: "ovrtx ovphysx"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhm the installs could fail but CI might keep going with those importorskip, no? and quietly telling a green outcome. Just confirming this is the intended behavior.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed: the extra package install runs inside the Docker test command under set -e, and .github/actions/run-tests/action.yml returns the container exit code after copying reports. So if pip install ovphysx fails, the job fails before pytest/importorskip can produce a green result. The importorskip guards are only for local or partial installs where the optional wheel was not requested.

Pass preloaded test source into the device_split detector so the per-file runner does not read the same test twice. Update the OVPhysX changelog fragment to list every test file now tagged for split CPU and GPU coverage.
@AntoineRichard
AntoineRichard merged commit ea1f61a into isaac-sim:develop Jun 9, 2026
60 of 61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

infrastructure isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants